/**
 * 高级下载管理器 - 支持暂停、继续、断点续传
 */

import ChatHistory from './ChatHistory.js'
import GameDownloadHistory from './GameDownloadHistory.js'

class AdvancedDownloadManager {
  
  // 静态属性
  static activeDownloads = new Map() // 活跃下载任务
  static downloadChunks = new Map()  // 下载分片数据
  static isNavigating = false
  
  /**
   * 开始分片下载
   * @param {Object} item 下载项
   * @param {string} downloadUrl 下载链接
   * @param {string} targetDir 目标目录
   */
  static async startChunkedDownload(item, downloadUrl, targetDir) {
    const itemName = this.getGameName(item)
    const gameType = item.type ? item.type.toLowerCase() : 'other'
    const downloadId = Date.now().toString()
    
    console.log(`开始分片下载: ${itemName}`)
    
    // 创建下载任务
    const downloadTask = {
      id: downloadId,
      itemName,
      gameType,
      targetDir,
      downloadUrl,
      status: 'starting', // starting, downloading, paused, completed, failed
      progress: 0,
      totalSize: 0,
      downloadedSize: 0,
      chunks: [],
      startTime: Date.now(),
      pausedAt: null,
      resumeCount: 0
    }
    
    this.activeDownloads.set(downloadId, downloadTask)
    
    try {
      // 1. 获取文件信息
      const fileInfo = await this.getFileInfo(downloadUrl)
      downloadTask.totalSize = fileInfo.size
      downloadTask.supportsRange = fileInfo.supportsRange
      
      if (!fileInfo.supportsRange) {
        console.log('服务器不支持断点续传，使用普通下载')
        return this.fallbackToNormalDownload(item, downloadUrl, targetDir)
      }
      
      // 2. 初始化分片存储
      this.initializeChunkStorage(downloadId, fileInfo.size)
      
      // 3. 开始下载
      downloadTask.status = 'downloading'
      this.updateDownloadProgress(downloadId)
      
      await this.downloadInChunks(downloadTask)
      
    } catch (error) {
      console.error('分片下载失败:', error)
      downloadTask.status = 'failed'
      downloadTask.error = error.message
      this.updateDownloadProgress(downloadId)
    }
  }
  
  /**
   * 获取文件信息
   * @param {string} url 下载链接
   * @returns {Promise} 文件信息
   */
  static getFileInfo(url) {
    return new Promise((resolve, reject) => {
      // #ifdef APP-PLUS
      uni.request({
        url: url,
        method: 'HEAD',
        success: (res) => {
          const contentLength = res.header['content-length'] || res.header['Content-Length']
          const acceptRanges = res.header['accept-ranges'] || res.header['Accept-Ranges']
          
          resolve({
            size: parseInt(contentLength) || 0,
            supportsRange: acceptRanges === 'bytes'
          })
        },
        fail: (error) => {
          // 如果HEAD请求失败，尝试GET请求获取信息
          uni.request({
            url: url,
            method: 'GET',
            header: {
              'Range': 'bytes=0-0'
            },
            success: (res) => {
              resolve({
                size: 0, // 未知大小
                supportsRange: res.statusCode === 206
              })
            },
            fail: reject
          })
        }
      })
      // #endif
      
      // #ifndef APP-PLUS
      resolve({
        size: 0,
        supportsRange: false
      })
      // #endif
    })
  }
  
  /**
   * 初始化分片存储
   * @param {string} downloadId 下载ID
   * @param {number} totalSize 总大小
   */
  static initializeChunkStorage(downloadId, totalSize) {
    const chunkSize = 1024 * 1024 // 1MB per chunk
    const chunks = []
    
    let offset = 0
    while (offset < totalSize) {
      const size = Math.min(chunkSize, totalSize - offset)
      chunks.push({
        offset: offset,
        size: size,
        downloaded: false,
        data: null,
        retryCount: 0
      })
      offset += size
    }
    
    this.downloadChunks.set(downloadId, chunks)
    console.log(`创建了 ${chunks.length} 个分片，总大小: ${this.formatFileSize(totalSize)}`)
  }
  
  /**
   * 分片下载
   * @param {Object} downloadTask 下载任务
   */
  static async downloadInChunks(downloadTask) {
    const chunks = this.downloadChunks.get(downloadTask.id)
    const maxConcurrent = 3 // 最大并发数
    const activeRequests = []
    
    for (let i = 0; i < chunks.length; i++) {
      if (downloadTask.status === 'paused') {
        console.log('下载已暂停')
        return
      }
      
      if (downloadTask.status === 'cancelled') {
        console.log('下载已取消')
        return
      }
      
      const chunk = chunks[i]
      if (chunk.downloaded) continue
      
      // 控制并发数
      if (activeRequests.length >= maxConcurrent) {
        await Promise.race(activeRequests)
      }
      
      const request = this.downloadChunk(downloadTask, chunk, i)
      activeRequests.push(request)
      
      request.finally(() => {
        const index = activeRequests.indexOf(request)
        if (index > -1) activeRequests.splice(index, 1)
      })
    }
    
    // 等待所有分片完成
    await Promise.all(activeRequests)
    
    if (downloadTask.status === 'downloading') {
      await this.combineChunks(downloadTask)
    }
  }
  
  /**
   * 下载单个分片
   * @param {Object} downloadTask 下载任务
   * @param {Object} chunk 分片信息
   * @param {number} chunkIndex 分片索引
   */
  static downloadChunk(downloadTask, chunk, chunkIndex) {
    return new Promise((resolve, reject) => {
      const endByte = chunk.offset + chunk.size - 1
      
      // #ifdef APP-PLUS
      uni.request({
        url: downloadTask.downloadUrl,
        method: 'GET',
        responseType: 'arraybuffer',
        header: {
          'Range': `bytes=${chunk.offset}-${endByte}`
        },
        success: (res) => {
          if (res.statusCode === 206 || res.statusCode === 200) {
            chunk.data = res.data
            chunk.downloaded = true
            
            // 更新下载进度
            downloadTask.downloadedSize += chunk.size
            downloadTask.progress = (downloadTask.downloadedSize / downloadTask.totalSize) * 100
            
            this.updateDownloadProgress(downloadTask.id)
            
            console.log(`分片 ${chunkIndex + 1} 下载完成`)
            resolve()
          } else {
            reject(new Error(`分片 ${chunkIndex} 下载失败: ${res.statusCode}`))
          }
        },
        fail: (error) => {
          chunk.retryCount++
          if (chunk.retryCount < 3) {
            console.log(`分片 ${chunkIndex} 重试第 ${chunk.retryCount} 次`)
            setTimeout(() => {
              this.downloadChunk(downloadTask, chunk, chunkIndex).then(resolve).catch(reject)
            }, 1000 * chunk.retryCount)
          } else {
            reject(error)
          }
        }
      })
      // #endif
      
      // #ifndef APP-PLUS
      resolve() // H5环境不支持
      // #endif
    })
  }
  
  /**
   * 合并分片
   * @param {Object} downloadTask 下载任务
   */
  static async combineChunks(downloadTask) {
    const chunks = this.downloadChunks.get(downloadTask.id)
    
    console.log('开始合并分片...')
    
    // #ifdef APP-PLUS
    try {
      // 创建临时文件
      const tempFileName = `${downloadTask.itemName}_${downloadTask.id}.tmp`
      const tempDir = '/storage/emulated/0/Android/data/io.dcloud.HBuilder/cache/'
      
      // 使用plus.io写入文件
      plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
        fs.root.getFile(tempFileName, { create: true }, (fileEntry) => {
          fileEntry.createWriter((writer) => {
            writer.onwriteend = () => {
              console.log('文件合并完成')
              downloadTask.status = 'completed'
              downloadTask.filePath = fileEntry.fullPath
              
              // 移动到目标目录
              this.moveToTargetDirectory(downloadTask)
              
              // 清理分片数据
              this.downloadChunks.delete(downloadTask.id)
            }
            
            // 按顺序写入分片数据
            let combinedData = new ArrayBuffer(downloadTask.totalSize)
            let view = new Uint8Array(combinedData)
            let offset = 0
            
            chunks.forEach(chunk => {
              if (chunk.data) {
                const chunkView = new Uint8Array(chunk.data)
                view.set(chunkView, offset)
                offset += chunkView.length
              }
            })
            
            const blob = new Blob([combinedData])
            writer.write(blob)
          })
        })
      })
    } catch (error) {
      console.error('合并分片失败:', error)
      downloadTask.status = 'failed'
      downloadTask.error = error.message
    }
    // #endif
  }
  
  /**
   * 暂停下载
   * @param {string} downloadId 下载ID
   */
  static pauseDownload(downloadId) {
    const downloadTask = this.activeDownloads.get(downloadId)
    if (downloadTask && downloadTask.status === 'downloading') {
      downloadTask.status = 'paused'
      downloadTask.pausedAt = Date.now()
      
      console.log(`下载已暂停: ${downloadTask.itemName}`)
      this.updateDownloadProgress(downloadId)
      
      uni.showToast({
        title: '下载已暂停',
        icon: 'success'
      })
      
      return true
    }
    return false
  }
  
  /**
   * 继续下载
   * @param {string} downloadId 下载ID
   */
  static async resumeDownload(downloadId) {
    const downloadTask = this.activeDownloads.get(downloadId)
    if (downloadTask && downloadTask.status === 'paused') {
      downloadTask.status = 'downloading'
      downloadTask.resumeCount++
      
      console.log(`继续下载: ${downloadTask.itemName}`)
      
      uni.showToast({
        title: '继续下载',
        icon: 'success'
      })
      
      // 从暂停点继续下载
      await this.downloadInChunks(downloadTask)
      
      return true
    }
    return false
  }
  
  /**
   * 取消下载（保留已下载数据）
   * @param {string} downloadId 下载ID
   * @param {boolean} keepData 是否保留数据
   */
  static cancelDownload(downloadId, keepData = true) {
    const downloadTask = this.activeDownloads.get(downloadId)
    if (!downloadTask) return false
    
    if (keepData && downloadTask.downloadedSize > 0) {
      // 保留数据，标记为暂停状态
      downloadTask.status = 'paused'
      downloadTask.pausedAt = Date.now()
      
      console.log(`下载已取消但保留数据: ${downloadTask.itemName}`)
      uni.showToast({
        title: '已取消下载，数据已保留',
        icon: 'success'
      })
    } else {
      // 完全取消，清理数据
      downloadTask.status = 'cancelled'
      this.downloadChunks.delete(downloadId)
      this.activeDownloads.delete(downloadId)
      
      console.log(`下载已完全取消: ${downloadTask.itemName}`)
      uni.showToast({
        title: '下载已取消',
        icon: 'success'
      })
    }
    
    this.updateDownloadProgress(downloadId)
    return true
  }
  
  /**
   * 获取下载状态
   * @param {string} downloadId 下载ID
   */
  static getDownloadStatus(downloadId) {
    return this.activeDownloads.get(downloadId)
  }
  
  /**
   * 获取所有下载任务
   */
  static getAllDownloads() {
    return Array.from(this.activeDownloads.values())
  }
  
  /**
   * 更新下载进度
   * @param {string} downloadId 下载ID
   */
  static updateDownloadProgress(downloadId) {
    const downloadTask = this.activeDownloads.get(downloadId)
    if (!downloadTask) return
    
    const progressData = {
      id: downloadId,
      gameName: downloadTask.itemName,
      gameType: downloadTask.gameType,
      status: downloadTask.status,
      progress: Math.round(downloadTask.progress || 0),
      progressText: `${Math.round(downloadTask.progress || 0)}%`,
      sizeText: `${this.formatFileSize(downloadTask.downloadedSize)}/${this.formatFileSize(downloadTask.totalSize)}`,
      speed: this.calculateSpeed(downloadTask),
      remainingTime: this.calculateRemainingTime(downloadTask),
      canPause: downloadTask.status === 'downloading',
      canResume: downloadTask.status === 'paused',
      canCancel: ['downloading', 'paused'].includes(downloadTask.status)
    }
    
    // 发送进度更新事件
    uni.$emit('advancedDownloadProgress', progressData)
  }
  
  /**
   * 计算下载速度
   * @param {Object} downloadTask 下载任务
   */
  static calculateSpeed(downloadTask) {
    if (!downloadTask.startTime) return '0KB/s'
    
    const elapsed = (Date.now() - downloadTask.startTime) / 1000
    const speed = downloadTask.downloadedSize / elapsed
    
    return `${this.formatFileSize(speed)}/s`
  }
  
  /**
   * 计算剩余时间
   * @param {Object} downloadTask 下载任务
   */
  static calculateRemainingTime(downloadTask) {
    if (downloadTask.progress <= 0) return '计算中...'
    
    const elapsed = (Date.now() - downloadTask.startTime) / 1000
    const speed = downloadTask.downloadedSize / elapsed
    const remaining = (downloadTask.totalSize - downloadTask.downloadedSize) / speed
    
    if (remaining < 60) return `${Math.round(remaining)}秒`
    if (remaining < 3600) return `${Math.round(remaining / 60)}分钟`
    return `${Math.round(remaining / 3600)}小时`
  }
  
  /**
   * 回退到普通下载
   * @param {Object} item 下载项
   * @param {string} downloadUrl 下载链接
   * @param {string} targetDir 目标目录
   */
  static fallbackToNormalDownload(item, downloadUrl, targetDir) {
    // 导入原有的下载管理器
    const DownloadManager = require('./DownloadManager.js').default
    return DownloadManager.startDownload(item, downloadUrl, targetDir)
  }
  
  // 工具方法 (从原有DownloadManager复制)
  static formatFileSize(bytes) {
    if (bytes === 0) return '0 B'
    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
  }
  
  static getGameName(game) {
    if (game.name && game.name.trim() !== '') {
      return game.name
    }
    
    if (game.id) {
      return `游戏 #${game.id}`
    }
    
    try {
      const url = game.publicUrl || game.lanUrl
      if (url) {
        const urlObj = new URL(url)
        const pathParts = urlObj.pathname.split('/')
        const filename = pathParts[pathParts.length - 1]
        if (filename && filename !== '') {
          const nameWithoutExt = filename.split('.')[0]
          return nameWithoutExt || '未知游戏'
        }
      }
    } catch (e) {
      console.log('无法从 URL 提取游戏名称')
    }
    
    return '未知游戏'
  }
  
  static moveToTargetDirectory(downloadTask) {
    // 实现文件移动逻辑 (从原有DownloadManager复制)
    console.log(`移动文件到目标目录: ${downloadTask.targetDir}`)
    
    // 触发下载完成事件
    uni.$emit('downloadComplete', {
      gameName: downloadTask.itemName,
      gameType: downloadTask.gameType,
      filePath: downloadTask.filePath,
      targetDir: downloadTask.targetDir
    })
    
    // 添加到下载历史
    GameDownloadHistory.addDownloadRecord({
      name: downloadTask.itemName,
      type: downloadTask.gameType
    }, downloadTask.filePath, downloadTask.gameType)
  }
}

export default AdvancedDownloadManager